package com.cyh;

/*

一、MyCat
     是java应用和mysql数据库之间的中间件。
     解决了： 1. java与数据库的紧耦合
            2. 高访问量高并发对数据库压力
            3. 读写请求数据不一样

     分库： 指本来在一个库中放的表， 分到两个库里放，即每个库中的表不一样。 -- 也称垂直拆分
     分表：即一个表中有千万级的数据， 将这张表分成多张表来存储， 并且要求分出的每张表在不同的数据库。  -- 水平拆分
     原理：比如北京的订单在数据库1中，上海的订单在数据库2中，mycat通过哪里的订单去访问哪个数据库。

二、 安装
     方式一、 rpm方式：.rpm安装包，多个.rpm时要按顺序安装
     方式二、 yum方式： 只需要联网就行
     方式三、 解压后即可用 --- 推荐。
            1.压缩包解压
            2.解压的文件夹拷贝到 /user/local/  的目录下
              注：文件夹有内容拷贝是：cp -r mycat /user/local/
     方式四、解压后编译安装
     命令-和--的区别，-表示后面的每个字母都是一个参数如：tar -zxvf path; --表示后面单词是一个参数如：--help

三、配置文件
     1. schema.xml : 定义逻辑库、表、分片节点等内容
     2. rule.xml ： 定义了分片规则
     3. server.xml  : 定义了用户以及系统的相关变量，如果端口等。

     架构：双主双从， 一主写一从读， 备用模块：也是一主写一从读。
     server.xml 修改 <user name="root">  root改成mycat
     schema.xml 修改 将关于所有的表删除， 在<schema 这一行的后面添加 dataNode = "dn1"
                  <schema/>  表示主题用的是哪个分片
                  <dataNode> 表示哪个分片对应哪个数据库
                  <dataHost>  心跳包，负责写的数据，负责读的数据，读写分离。

     验证远程访问方式：mysql -uroot -p123123 -h 192.168.140.127 -P 3306
     mycat启动：控制台启动方式： ./mycat console  ---先用这种可以看到打印信息。
               后台启动方式： ./mycat start

     mycat登录：方式一、登录后台管理窗口，用于管理维护mycat: mysql -umycat -p123456 -P 9066 -h 192.168.140.128
               方式二、登录数据窗口，用于查询数据--先用这种： mysql -umycat -p123456 -P 9066 -h 192.168.140.128
               得到的命令头跟mysql一样： mysql>
               show databases
               use testdb

四、搭建读写分离
     读写分离需要主从复制配合
     1.一主一从：
         redis和mysql主从复制，主机都只能有一台，从机可以有多台。主机负责写，从机负责读。
       mysql主从复制的原理：主机将写操作写入二进制的log日志，binary log, 从机读取日志到本地，在写入Relay log, 在读取这个log.
       主从复制有一定的延迟性。
       修改主机的mysql配置文件： /etc/my.cnf
            server-id=1  每台机器要不一样
            log-bin=mysql-bin  要启动这个日志，否则无法做到主从复制
            binlog-ignore-db=mysql
            binlog-ignore-db=information_schema  设置不要复制的数据，类似这种系统的数据要忽略掉
            binlog-do-db=testdb  需要复制的数据库的名字
            binlog_format=STATEMENT 设置logbin格式。statement模式：整表所有写操作复制，速度快，但是有函数now()这种的，会导致时间不一致
                                                  ROW模式： 一行一行复制，数据量大时，速度慢
                                                  MIXED模式：解决statement一部分的数据不一致的问题，但@@host name这些系统变量会有问题。
      修改从机的mysql配置文件：/etc/my.cnf
           server-id=2
           relay-log=mysql-relay  启动中继日志

      重启主从mysql
      查看mysql启动转态
      关闭防火墙

      在主机上创立账户并授权给slave从机
      主机执行：GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%'IDENTIFIED BY '123123'

      查看主机的状态
      show master status

      从机
      stop slave
      reset master
      再执行， 修改切入点，随主机的重启会重新改变，重新配置。  ------打一个标签1（后面直接看到这里）
      CHANGE MASTER TO
      MASTER_HOST='192.168.140.128',  主机host
      MASTER_USER='slave',
      MASTER_PASSWORD='123123,
      MASTER_LOG_FILE='mysql-bin.00003',  上面查看主机状态时显示的file
      MASTER_LOG_POS=722;  上面查看主机状态时显示的数字

      start slave;
      查看从机的状态
      show slave status
      或
      show slave status\G:
      如果显示Slave_IO_Running:Yes和Slave_SQL_Running:Yes，说明搭建成功。
      如果不是yes, 这次打印的某些日志会显示错误信息。

      创建数据库也要在主从复制搭建后创建，从机才会自动创建。


      这时切换到mycat命令窗口，启动登录mycat
      在这里操作mysql命令，这样写操作命令就是在主机上了，读命令就是在从机上了。


      如果主机上写入命令：insert into mytbl values(1, @@hostname); 这样主从机器的数据就不一样了,主机显示的89host名字，从机显示的是70host的名字
      再在mycat里面命令查询：select * from mytbl;  显示是主机的名字，出错了
      因为mycat的schema.xml配置文件中要修改
          <dataHost balance=""> 单主单从写3， 双主双从写1， 其他的不要选， 我们上面出错的可以试着写2，则每次查询的结果会不一样。
          balance要改变：
             balance="0" 不开启读写分离，都操作在写主机上面
             balance="1"  写主机负责写， 所有读主机和备用的写主机负责负载均衡读。
             balance="2"  写主机负责写， 写主机备用写主机所有读主机负责负载均衡读
             balance="3"  写主机负责写， 所有读主机负责读。

    2. 双主双从
        m1是主机，m2是备用主机，如果m1宕机了，m2变成主机了，m1重新启动了，m1就变成备用主机了。s1是m1的从机，s2是m2的从机
        m1需要修改配置，在单主单从的基础上添加
            添加
            log-slave-updates  表示在作为从数据库时，有写入操作需要更新
            auto-increment-increment=2  表示自增长字段的起始值
            auto-increment-offset=1 指一次递增多少
        m2需要修改的配置: 其他的跟m1第一步单主单从时的配置之外，还需要添加
            server-id=3
            log-slave-updates
            auto-increment-increment=2
            auto-increment-offset=2
        s1和s2的机器跟单主单从的配置一样，只是server-id要保证唯一

        重启两台主机
        查看运行状态

        查看两台主机的状态
        show master status

        两台从机从机都要像单主单从那样修改切入点，切入点随主机的重启都会改变 ---请参考上面标签1的内容

        启动两台从机

        到这一步，m1和s1之间的主从复制搭建好了，m2和s2之间的主从复制搭建好了，但是m1和m2直接的关系还没有配置好。
        m1和m2要相互复制
        做法------请参考上面标签1的内容
        m1和m2都要运行 标签1  的命令，

        查看4台机器的信息，如果都显示Slave_IO_Running:Yes和Slave_SQL_Running:Yes，说明搭建成功。

        上面搭建好了双主双从的复制，下面要搭建双主双从的读写分离

        停止mycat
        修改mycat配置文件
        balance="1"
        重新复制添加一份<writeHost>
        <dataHost> 里面writeType="0" 表示默认写操作写入第0台机器上。 不要写其他数字，不支持
                   switchType="1" 默认值，自动切换， -1表示不自动切换，2基于mysql主从同步的状态决定是否切换
       重启mycat,在mycat命令，运行mysql命令：insert into mytbl values(1, @@hostname); 进行测试
       把写主机宕机， 查看一下mysql的运行状态， 测试一下。


五、垂直分库----不同的表放到不同的库
   客户表，订单表，订单详情表，字典表  --- 怎样分库
   原则：两个数据库在同一个mysql（或主机）中可以关联查询，否则不能关联查询。
   所有客户表和跟客户表相关联的表在一个库，订单表、订单详情表、字典表和他们相关联的表在另外一个库。
   修改schema配置文件：
     <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100", dataNode="dn1">
        <table name="customer" dataNode="dn2"></table>  将客户表放到另外一个分片中即服务器中
     </schema>
     <dataNode name="dn1" dataHost="host1" database="orders"/>
     <dataNode name="dn2" dataHost="host2" database="orders"/>
     <dataHost name="host1"></dataHost>
     <dataHost name="host2"></dataHost>  如果做得简单点，里面只需要写主机，不需要读主机即可

     在dn1机器上，创建orders数据库
     在dn2机器上，也创建orders数据库

     在mycat命令中，创建customer表，dn1中不会创建， dn2中会创建，---表示正确，垂直分库了。
                  创建orders表、ordersDetail表、orders_type表， dn1中会创建，dn2机器不会创建 --- 正确，垂直分库。

六、水平拆分  --- 分表 --- 分到多台机器上
    一张表数据超过600万就得分表，超过1000万就达到瓶颈了。
    分片划分有规则的，订单不能用主键日期和时间划分，因为这样压力会集合在一台机器上，应该将压力分配到不同机器上。可以通过客户id来划分分片。
                  可以通过客户id%主机数量 来划分分片。
                  不同的表有不同的划分原则。
    修改schema.xml配置文件
    <schema>
        <table name="orders" dataNode="dn1,dn2" rule="mod_rule></table>
    </schema>
    修改rule.xml配置文件---分片规则
    复制一份数据进行下面的修改
    <tableRule name="mod_rule">
        <rule>
            <columns>customer_id</columns>
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>
    在文件下面找到mod-long的算法，将<property name="count">2</property>  默认值是3，我们改成2， 里面有很多算法。

    用mysql在dn2机器上面创建order表。

    用mycat在插入命令插入数据，注意：这个命令不能像以前一样省略字段名字，否则会报错，因为有一个字段做了分片，所以不能省略名字。
    用mycat查询所以数据，他会从不同的库中查询数据，且顺序是一个库查询完后再查询另外一个库，所以id不是从小到大的，而是混乱的，所以order by id 加这一句

    关联查询 --- join
    因为orderDetail每分片，只在一台机器上有，所以关联查询会报错。所以orderDetail也要分片， 通过order_id来分片
    修改 schema.xml 配置文件, 在原有的配置上，加一句
    <schema>
        <table name="orders" dataNode="dn1,dn2" rule="mod_rule>
            <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id"> </childTable>
        </table>
    </schema>

    用mysql在dn2上创建orders_detail表。
    用mycat插入数据
    用mycat关联join查询数据

    全局表：
       1.变动不频繁
       2.数据量总体变化不大
       3.数据规模不大，很少有超过10万条记录的。
     特性： 1，dn1和dn2都要插入
           2，全局表的查询，只需要在自己机器上查询
           3， 全局表可以跟任何表join查询
    修改schema.xml文件，加一句代码
    <table name="dict_order_type" dataNode="dn1,dn2" type="global"></table>
    用mysql在dn2上创建  dict_order_type 表。
    用mycat插入数据。
    需要满足dn1和dn2这张表的数据相同。


    常用的分片规则
       1. 取模 --- 上面用的就是这种
       2. 分片枚举， 如根据北京的数据存在一台机器上， 江西的数据存在另外一台机器上。
          修改schema.xml配置文件 -- 新增一条，订单区域表，这一张表按区域枚举来划分分片
          <table name="orders_ware_info" dataNode="dn1,dn2" rule=sharding_by_infile"></table>
          修改rule.xml配置文件 新增
          <tableRule name="sharding_by_infile">
            <rule>
                <columns>areacode</columns>
                <algorithm>hash-int</algorithm>
            <rule>
          </tableRule>
          修改
          <function name="hash-int">
               <property name="mapFile">partition-hash-int.txt</property>
               <property name="type">1</property>   0是int型， 非0是String
               <property name="defaultNode>0</property> 小于0不设置默认节点，大于等于0设置默认节点
          </function>
          修改文件partition-hash-int.txt文件。添加下面两句
          110=0
          111=1
          使用mycat创建表，则dn1和dn2都要这张表
          使用mycat插入数据。
       3. 范围约定
           比如支付信息表， 编号0-102在dn1机器, 103-200在dn2机器
           找到mycat配置文件autopartition-long.txt添加下面两句
             0-102=0
             103-200=1
           修改schema.xml配置文件
             <table name="payment-info" dataNode="dn1,dn2" rule="auto_sharding_long"></table>
           修改rule.xml配置文件 -- 增加
             <tableRule name="auto_sharding_long">
                <rule>
                    <columns>order_id</columns>
                    <algorithm>rang-long</algorithm>
                <rule>
             </tableRule>
             修改
              <function name="rang-long">
                   <property name="mapFile">autopartition-long.txt</property>
                   <property name="defaultNode>0</property> 小于0不设置默认节点，大于等于0设置默认节点
              </function>
          使用mycat创建表，则dn1和dn2都要这张表
          使用mycat插入数据。

      4.按日期或天分片
         比如用户信息表，有个登录日期进行分片
         修改schema.xml配置文件
         <table name="login-info" dataNode="dn1,dn2" rule="sharding_by_date"></table>
         修改rule.xml配置文件 -- 增加
         <tableRule name="sharding_by_date">
            <rule>
                <columns>login_date</columns>
                <algorithm>shardingByDate</algorithm>
            <rule>
         </tableRule>
         修改
          <function name="shardingByDate">
               <property name="dateFormat">yyyy-MM-dd</property>  日期格式
               <property name="sBeginDate">2019-01-01</property>  开始日期
               <property name="sEndDate">2019-01-04</property>   结束日期，达到这个日期的分片后循环从开始分片插入
               <property name="sPartionDay">2</property>  分区天数，每隔2天分一个区。
          </function>
         使用mycat创建表，则dn1和dn2都要这张表
         使用mycat插入数据。



     全局序列---分表会导致id自增但是两个库里的相同表id会相同。
        1.本地文件的方式，---抗风险态低，如果mycat宕机了，备用的mycat没有这个本地文件，导致id重复
        2.数据库方式  --- 推荐使用 ---这些都是官网上的, 已经代码都不需要自己写或者改。
           在dn1上创建全局序列表
           CREATE TABLE MYCAT_SEQUENCE(NAME VARCHER(50) NOT NULL, current_value INT NOT NULL,
           increment INT NOT NULL DEFAULT 100, PRIMARY KEY(NAME)) ENGINE=INNODB;
           创建全局序列所需要的函数
           DELIMITER $$
           CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS VARCHAR(64)
           BEGIN
           DECLARE retval VARCHAR(64);
           SET retval="-99999999, null";
           SELECT CONCAT(CAST(current_value AS CHAR),"",CAST((increment AS CHAR)) INTO retval FROM
           MYCAT_SEQUENCE WHERE NAME=seq_name;
           RETURN retval;
           END $$
           DELIMITER;

           DELIMITER $$
           CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50), VALUE INTEGER) RETURNS
           VARCHAR(64)
           DETERMINISTIC
           BEGIN
           UPDATE MYCAT_SEQUENCE
           SET current_value = VALUE
           WHERE NAME=seq_name;
           RETURN mycat_seq_currval(seq_name);
           END $$
           DELIMITER;


           DELIMITER $$
           CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS VARCHAR(64)
           DETERMINISTIC
           BEGIN
           UPDATE MYCAT_SEQUENCE
           SET current_value=current_value + increment WHERE NAME = seq_name;
           RETURN mycat_seq_currval(seq_name);
           END $$;
           DELIMITER ;

           初始化序列表记录
           INSERT INTO MYCAT_SEQUENCE(NAME, current_value, increment) VALUESE ('ORDERS', 400000, 100);

           修改mycat配置文件 sequence_db_conf.properties
           ORDERS=dn1
           看一下里面的参数是不是我们的dn1.

           修改mycat配置文件server.xml
           <property name="sequnceHandlerType">1</property> 0:本地文件方式，1：数据库方式，2时间戳方式，3自动生成全局方式。默认是2，我们要改成1.

           mycat插入数据用下面这个
           insert into orders(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDERS, 1000, 101, 102);
           即id值要替换成next value for MYCATSEQ_ORDERS

           如果dn1宕机了，id也不会重复






        3.时间戳方式 -- 不用这种，id长度达到18位，太长
        4.自动生成全局序列 --- 太麻烦，耦合性太高
           根据业务逻辑，java代码自己设置id
           利用redis的incr来生成序列



七、基于HA机制的MYCAT高可用性 --- 解决mycat也会宕机的问题
    使用mycat集群。
    原理：使用HAProxy+Keepalived配合两台mycat搭起mycat集群，实现高可用性，HAProxy实现了mycat多节点的集群高可用和负载均衡，
         而HAProxy自身的高可用则可以通过Keepalived来实现。

    主机：安装HAProxy、Keepalived、mycat
    备用主机一：安装HAProxy、Keepalived、mycat

    安装HAProxy
       解压到/usr/local/src中
       查看内核版本 uname -r
       编译：make TARGET=linux310 PREFIX=/usr/local/haproxy ARCH=x86_64
       TARTET---内核版本
       ARCH --- 系统的位数
       PREFIX --- 安装路径
       安装：make install PREFIX=/usr/local/haproxy
       创建目录，创建配置文件
       mkdir -p /usr/data/haproxy/
       vim /usr/local/haproxy/haproxy.conf
       haproxy.conf里面的配置文件需要增加很多信息，，具体可以看有关HAProxy的视频
          global
               log 127.0.0.1  local0
               #log 127.0.0.1   local1 notice
               #log loghost   local0 info
               maxconn 4096
               chroot /usr/local/haproxy
               pidfile /usr/data/haproxy/haproxy.pid
               uid 99
               gid 99
               daemon
               #debug
               #quiet
          defaults
               log global
               mode tcp
               option abortonclose
               option redispath
               retries 3
               maxconn 2000
               timeout connect 5000
               timeout client 50000
               timeout server 50000
          listen proxy_status
              bind: 48066
                   mode tcp
                   balance roundrobin
                   server mycat_1 192.168.140.128:8066 check inter 10s
                   server mycat_2 192.168.140.127:8066 check inter 10s
          frontend admin_stats
              bind: 7777
                   mode http
                   stats enable
                   option httplog
                   maxconn 10
                   stats refresh 30s
                   stats uri /admin
                   stats auth admin:123123
                   stats hide-version
                   stats admin if TRUE


       启动HAProxy
       /usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/haproxy.conf
       查看HAProxy进程
       ps -ef|grep haproxy
       打开浏览器访问一下
       http://192.168.140.125:7777/admin
       输入用户和密码：haproxy.conf里面有 admin  123123
       验证负载均衡
       使用mycat访问：mysql -umycat -p123456 -h 192.168.140.126 -P 48066

   安装Keepalived
      解压到/usr/local/src
      安装相应的插件：yum install -y gcc openssl-devel popt-devel
      进入目录：cd /usr/local/src/keepalived-1.4.2
      命令：./configure --prefix=/usr/local/keepalived
      编译安装： make && make install
      运行前配置
      cp /usr/local/src/keepalived-1.4.2/keepalived/etc/init.d/keepalived /etc/init.d/
      mkdir /etc/keepalived
      cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
      cp /usr/local/src/keepalived-1.4.2/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
      cp /usr/local/keeepalived/sbin/keepalived /usr/sbin/
      修改配置文件
      vim /etc/keepalived/keepalived.config
      清空这个文件，使用下面这些配置
         !Configuration File for keepalived
         global_defs {
            notification_email {
                xlcocoom@foxmail.com
            }
            notification_email_from keepalived@showjoy.com
            smtp_server 127.0.0.1
            smtp_connect_timeout 30
            router_id LVS_DEVEL
            vrrp_skip_check_adv_addr
            vrrp_garp_interval 0
            vrrp_gna_interval 0
         }

         vrrp_instance VI_1{
            #主机配置MASTER, 备机配置BACKUP;
            state MASTER
            #所在机器的网卡
            interface ens33
            virtual_router_id 51
            #数值越大优先级越高
            priority 100
            advert_int 1
            authentication {
                auth_type PASS
                auth_pass 1111
            }
            virtual_ipaddress{
                #虚拟IP
                192.168.140.200
            }
         }
         virtual_server 192.168.140.200 48066 {
            delay_loop 6
            lb_algo rr
            lb_kind NAT
            persistence_timeout 50
            protocol TCP
            real server 192.168.140.125 48066 {
                weight 1
                TCP_CHECK {
                    connect_timeout 3
                    retry 3
                    delay_before_retry 3
                }
            }
            real_server 192.168.140.126 48600 {
                weight 1
                TCH_CHECK {
                  connect_timout 3
                  nb_get_retry 3
                  delay_before_retry 3
                }
            }
         }
      启动keepalived
      service keepalived start
      登录验证
      mysql -umycat -p123456 -h 192.168.140.200 -P 48066

  备用主机一样要安装这两个软件。
  主机宕机了，从机过一段时间会自动替换主机。
  HAProxy通过虚拟ip来进行保护它。


八、Mycat安全权限配置usr
    1.user标签进行权限配置 -- 精确到数据库
       mycat的server.xml配置文件修改
       <user name="mycat>
            <property name="password">123456</property>
            <property name="schemas">TESTDB</property>
       </user>
       <user name="user>
            <property name="password">user</property>
            <property name="schemas">TESTDB</property>
            <property name="readOnly">true</property>
       </user>

    2. privileges 标签权限控制， --- 精确到表
       0000： 四位分表代表：增加，更新，查询，删除
       修改server.xml配置文件
        <user name="mycat>
            <property name="password">123456</property>
            <property name="schemas">TESTDB</property>
            <privileges check="true">
                <schema name="TESTDB" dml="1111">
                    <table name="orders" dml="0000"></table>
                </schema>
            </privileges>
        </user>

        重启一下mycat

 九、 SQL拦截
     白名单和黑名单： 修改server.xml配置文件,最外层添加
     <firewall>
        <whitehost>
            <host host="192.168.140.128" user="mycat"/>
        </whitehost>
        <blacklist check="true">
            <property name="deleteAllow">false</property>
        </blacklist>
     </firewall>
     黑名单项：
       selectAllow deleteAllow updateAllow insertAllow createTableAllow setAllow alterTableAllow
       dropTableAllow commitAllow rollbackAllow

十、Mycat监控工具
    1. Mycat-web
       下载安装zookeeper
       下载安装Mycat-web
       小心防火墙，linux防火墙，mycat防火墙。





**/
public class Test04 {
}
